import re,codecs
import sklearn_crfsuite
from sklearn_crfsuite import metrics
#from sklearn.externals import joblib
import joblib

class CorpusProcess:
    def __init__(self):
        self.train_corpus_path = "199801_people_s_daily.txt"
        self.process_corpus_path = "result-rmrb.txt"
        self._maps = {u't': u'T',u'nr': u'PER', u'ns': u'LOC',u'nt': u'ORG',u"i":"IOM"}

    def read_corpus_from_file(self, file_path):
        f = codecs.open(file_path, 'r','utf-8')#,encoding='utf-8'
        lines = f.readlines()
        f.close()
        return lines

    def write_corpus_to_file(self, data, file_path):
        f = codecs.open(file_path, 'wb','utf-8')
        f.write(data)
        f.close()
        
    @classmethod
    def q_to_b(self,q_str):
        """全角转半角"""
        b_str = ""
        for uchar in q_str:
            inside_code = ord(uchar)
            if inside_code == 12288:  # 全角空格直接转换
                inside_code = 32
            elif 65374 >= inside_code >= 65281:  # 全角字符（除空格）根据关系转化
                inside_code -= 65248
            b_str += chr(inside_code)
        return b_str
    @classmethod
    def b_to_q(self,b_str):
        """半角转全角"""
        q_str = ""
        for uchar in b_str:
            inside_code = ord(uchar)
            if inside_code == 32:  # 半角空格直接转化
                inside_code = 12288
            elif 126 >= inside_code >= 32:  # 半角字符（除空格）根据关系转化
                inside_code += 65248
            q_str += chr(inside_code)
        return q_str

    def pre_process(self):
        """语料预处理 """
        lines = self.read_corpus_from_file(self.train_corpus_path)
        new_lines = []
        for line in lines:
            words = self.q_to_b(line.strip()).split(u'  ')
            pro_words = self.process_t(words)
            pro_words = self.process_nr(pro_words)
            pro_words = self.process_k(pro_words)
            new_lines.append('  '.join(pro_words[1:]))
        self.write_corpus_to_file(data='\n'.join(new_lines), file_path=self.process_corpus_path)

    def process_k(self, words):
        """处理大粒度分词,合并语料库中括号中的大粒度分词,类似：[国家/n  环保局/n]nt """
        pro_words = []
        index = 0
        temp = u''
        while True:
            word = words[index] if index < len(words) else u''
            if u'[' in word:
                temp += re.sub(pattern=u'/[a-zA-Z]*', repl=u'', string=word.replace(u'[', u''))
            elif u']' in word:
                w = word.split(u']')
                temp += re.sub(pattern=u'/[a-zA-Z]*', repl=u'', string=w[0])
                pro_words.append(temp+u'/'+w[1])
                temp = u''
            elif temp:
                temp += re.sub(pattern=u'/[a-zA-Z]*', repl=u'', string=word)
            elif word:
                pro_words.append(word)
            else:
                break
            index += 1
        return pro_words

    def process_nr(self, words):
        """ 主席/n江/nr某某/nr===>>>'主席/n江某某/nr'"""
        pro_words = []
        index = 0
        while True:
            word = words[index] if index < len(words) else u''
            if u'/nr' in word:
                next_index = index + 1
                if next_index < len(words) and u'/nr' in words[next_index]:
                    pro_words.append(word.replace(u'/nr', u'') + words[next_index])
                    index = next_index
                else:
                    pro_words.append(word)
            elif word:
                pro_words.append(word)
            else:
                break
            index += 1
        return pro_words

    def process_t(self, words):
        """处理时间,合并语料库分开标注的时间词，类似： （/w  一九九七年/t  十二月/t  三十一日/t  ）/w   """
        pro_words = []
        index = 0
        temp = u''
        while True:
            word = words[index] if index < len(words) else u''
            if u'/t' in word:
                temp = temp.replace(u'/t', u'') + word
            elif temp:
                pro_words.append(temp)
                pro_words.append(word)
                temp = u''
            elif word:
                pro_words.append(word)
            else:
                break
            index += 1
        return pro_words

    def pos_to_tag(self, p):
        """由词性提取标签"""
        t = self._maps.get(p, None)
        return t if t else u'O'

    def tag_perform(self, tag, index):
        """标签使用BIO模式"""
        if index == 0 and tag != u'O':
            return u'B_{}'.format(tag)
        elif tag != u'O':
            return u'I_{}'.format(tag)
        else:
            return tag
    def tag_perform_new(self, tag, index,length_index):
        """标签使用BMEWO模式"""
        if index == 0 and tag != u'O':
            return u'B_{}'.format(tag)
        elif tag != u'O' and index != length_index-1:
            return u'M_{}'.format(tag)
        elif index == length_index-1 and tag != u'O':
            return u'E_{}'.format(tag)
        else:
            return tag
    def pos_perform(self, pos):
        """去除词性携带的标签先验知识"""
        if pos in self._maps.keys() and pos != u't':
            return u'n'
        else:
            return pos

    def initialize(self):
        """初始化 """
        lines = self.read_corpus_from_file(self.process_corpus_path)
        words_list = [line.strip().split('  ') for line in lines if line.strip()]
        del lines
        self.init_sequence(words_list)

    def init_sequence(self, words_list):
        """初始化字序列、词性序列、标记序列 """
        words_seq = [[word.split(u'/')[0] for word in words] for words in words_list]
        pos_seq = [[word.split(u'/')[1] for word in words] for words in words_list]
        tag_seq = [[self.pos_to_tag(p) for p in pos] for pos in pos_seq]
        self.pos_seq = [[[pos_seq[index][i] for _ in range(len(words_seq[index][i]))]
                        for i in range(len(pos_seq[index]))] for index in range(len(pos_seq))]
        self.tag_seq = [[[self.tag_perform_new(tag_seq[index][i], w) for w in range(len(words_seq[index][i]))]
                        for i in range(len(tag_seq[index]))] for index in range(len(tag_seq))]
        self.pos_seq = [[u'un']+[self.pos_perform(p) for pos in pos_seq for p in pos]+[u'un'] for pos_seq in self.pos_seq]
        self.tag_seq = [[t for tag in tag_seq for t in tag] for tag_seq in self.tag_seq]
        self.word_seq = [[u'<BOS>']+[w for word in word_seq for w in word]+[u'<EOS>'] for word_seq in words_seq]
    @classmethod
    def extract_feature(self, word_grams):
        """特征选取"""
        features, feature_list = [], []
        for index in range(len(word_grams)):
            for i in range(len(word_grams[index])):
                word_gram = word_grams[index][i]
                #feature = {u'w-1': word_gram[0], u'w': word_gram[1], u'w+1': word_gram[2],
                           #u'w-1:w': word_gram[0]+word_gram[1], u'w:w+1': word_gram[1]+word_gram[2],
                           ## u'p-1': self.pos_seq[index][i], u'p': self.pos_seq[index][i+1],
                           ## u'p+1': self.pos_seq[index][i+2],
                           ## u'p-1:p': self.pos_seq[index][i]+self.pos_seq[index][i+1],
                           ## u'p:p+1': self.pos_seq[index][i+1]+self.pos_seq[index][i+2],
                           #u'bias': 1.0}
                feature = {u'w-2':word_gram[0],u'w-1':word_gram[1],u'w':word_gram[2],u'w+1':word_gram[3],
                                       u'w+2':word_gram[4],u'w-2:w-1:w':word_gram[0]+word_gram[1]+word_gram[2],u'w-1:w:w+1':word_gram[1]+word_gram[2]+word_gram[3],
                                       u'w:w+1:w+2':word_gram[2]+word_gram[3]+word_gram[4],u'w-1:w':word_gram[1]+word_gram[2],
                                       u'w:w+1':word_gram[2]+word_gram[3]}
                feature_list.append(feature)
            features.append(feature_list)
            feature_list = []
        return features
    @classmethod
    def segment_by_window(self, words_list=None, window=5):
        """窗口切分"""
        words = []
        begin, end = 0, window
        for _ in range(1, len(words_list)):
            if end > len(words_list): break
            words.append(words_list[begin:end])
            begin = begin + 1
            end = end + 1
        return words

    def generator(self):
        """训练数据"""
        word_grams = [self.segment_by_window(word_list) for word_list in self.word_seq]
        features = self.extract_feature(word_grams)
        return features, self.tag_seq